package com.yhb.channel;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yhb.channel.dao.flow.ExecutionFlow;
import com.yhb.channel.dao.flow.ExecutionFlowMapper;
import com.yhb.channel.utils.ChannelJSONUtil;
import com.yhb.controller.admin.form.QueryExecutionFlowForm;
import com.yhb.controller.admin.vo.PageVo;
import com.yhb.controller.admin.vo.UnionFlowQueryVo;
import com.yhb.model.ChannelBoundRelationship;
import lombok.extern.log4j.Log4j;
import lombok.var;
import me.edzh.spring.bootstrap.utils.JSONUtil;
import me.edzh.spring.bootstrap.utils.ResultCode;
import me.edzh.spring.bootstrap.utils.exception.ServiceException;
import org.apache.commons.lang.StringUtils;
import org.apache.http.util.TextUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Log4j
public class FlowService {
    @Autowired
    ExecutionFlowMapper executionFlowMapper;


    @NotNull
    private String dateFormat(Date date) {
        return new SimpleDateFormat("yyyyMMdd").format(date);
    }

    @NotNull
    private String getTodayDateString() {
        return dateFormat(new Date());
    }

//    @NotNull
//    private String getYesterdayDateString() {
//        final Calendar calendar = Calendar.getInstance();
//        calendar.add(Calendar.DATE, -1);
//        Date date = calendar.getTime();
//        return dateFormat(date);
//    }

    /**
     * 插入流水
     * @param executionFlow 插入的流水
     * @return 插入成功的executionFlow的id
     */
    public String add(@NotNull ExecutionFlow executionFlow) {
        executionFlow.setStatus(ExecutionFlow.FlowStatus.INITIALIZED);
        String dateString = getTodayDateString();
        executionFlowMapper.insert(executionFlow, dateString);
        return executionFlow.getId();
    }

//    /**
//     * 获取今天或者昨天的流水
//     * @param id 流水id
//     * @return 流水对象
//     */
//    public ExecutionFlow get(String id) {
//        String todayDateString = getTodayDateString();
//        String yesterdayDateString = getYesterdayDateString();
//        ExecutionFlow executionFlow = executionFlowMapper.getExecutionFlowById(id, todayDateString);
//        if (executionFlow == null) {
//            executionFlow = executionFlowMapper.getExecutionFlowById(id, yesterdayDateString);
//        }
//        return executionFlow;
//    }

    /**
     * 精确获取和更新流水 用createTime + id匹配
     * @param id 流水id
     * @param dateString 哪天的流水
     * @return 流水
     */
    public ExecutionFlow getFlowPrecisely(String id, String dateString) {
        return executionFlowMapper.getExecutionFlowById(id, dateString);
    }
    public ExecutionFlow getFlowPrecisely(String id, Date date) {
        return getFlowPrecisely(id, dateFormat(date));
    }
    public int updatePrecisely(ExecutionFlow flow, Date date) {
        return executionFlowMapper.updateExecutionFlow(flow, dateFormat(date));
    }

    /**
     * 精确获取流水 用createTime + requestId匹配
     * @param flow 流水信息
     * @return 流水对象
     */
    public ExecutionFlow getByRequestIdAndCreateTime(@NotNull ExecutionFlow flow) {
        if (null == flow.getCreateTime()) {
            log.warn("getByRequestIdAndCreateTime createTime empty: " + ChannelJSONUtil.toJson(flow));
        }
        if (null == flow.getRequestId()) {
            log.warn("getByRequestIdAndCreateTime requestId empty: " + ChannelJSONUtil.toJson(flow) );
        }
        var createTime = dateFormat(flow.getCreateTime());
        var requestId = flow.getRequestId();
        return executionFlowMapper.getExecutionFlowByRequestId(requestId, createTime);
    }

//    /**
//     * 更新某条流水
//     * @param executionFlow 新的流水信息
//     * @return 成功与否
//     */
//    public boolean update(@NotNull ExecutionFlow executionFlow) {
//        // 通过id找到该流水
//        ExecutionFlow targetExecutionFlow = get(executionFlow.getId());
//        if (targetExecutionFlow == null) {
//            return false;
//        }
//        // 找到了就看创建时间 就知道在哪张表
//        Date flowCreateTime = targetExecutionFlow.getCreateTime();
//        String dateString = dateFormat(flowCreateTime);
//        // 去对应表通过id找到并更新它
//        executionFlowMapper.updateExecutionFlow(executionFlow, dateString);
//        return true;
//    }

//    /**
//     * 更新某条流水
//     * @param executionFlow 新的流水信息
//     * @return 成功与否
//     */
//    public boolean updateByRequestId(@NotNull ExecutionFlow executionFlow) {
//        // 通过requestId找到该流水
//        ExecutionFlow targetExecutionFlow = getByRequestId(executionFlow);
//        if (targetExecutionFlow == null) {
//            return false;
//        }
//        // 找到了就看创建时间 就知道在哪张表
//        Date flowCreateTime = targetExecutionFlow.getCreateTime();
//        String dateString = dateFormat(flowCreateTime);
//        // 去对应表通过requestId找到并更新它
//        executionFlowMapper.updateExecutionFlowByRequestId(executionFlow, dateString);
//        return true;
//    }

//    /**
//     * 在已经精确找到目标流水的情况下调用
//     * @param targetExecutionFlow 目标流水
//     * @param executionFlow 新流水信息
//     */
//    public void update(@NotNull ExecutionFlow targetExecutionFlow, ExecutionFlow executionFlow) {
//        Date flowCreateTime = targetExecutionFlow.getCreateTime();
//        String dateString = dateFormat(flowCreateTime);
//        executionFlowMapper.updateExecutionFlow(executionFlow, dateString);
//    }

    /**
     * 在已经精确找到目标流水的情况下调用
     * 根据targetExecutionFlow的createTime和requestId更新流水
     * @param targetExecutionFlow 目标流水
     * @param executionFlow 新流水信息
     */
    public void updateByRequestId(@NotNull ExecutionFlow targetExecutionFlow, ExecutionFlow executionFlow) {
        Date flowCreateTime = targetExecutionFlow.getCreateTime();
        String dateString = dateFormat(flowCreateTime);
        executionFlowMapper.updateExecutionFlowByRequestId(executionFlow, dateString);
    }

//    public boolean setStatus(@NotNull ExecutionFlow executionFlow, ExecutionFlow.FlowStatus status) {
//        ExecutionFlow oldExecutionFlow = get(executionFlow.getId());
//        if (oldExecutionFlow == null || oldExecutionFlow.getStatus() != ExecutionFlow.FlowStatus.INITIALIZED) {
//            return false;
//        }
//        executionFlow.setStatus(status);
//        update(oldExecutionFlow, executionFlow);
//        return true;
//    }

    /**
     * 通过executionFlow的requestId + createTimed更新流水
     * @param executionFlow requestId + createTime + extendInfo + Status的信息载体
     * @return 数据库里的目标流水
     */
    public ExecutionFlow setStatusByRequestIdAndCreateTime(@NotNull ExecutionFlow executionFlow) {
        // 事先检查状态 防止重复设置
        ExecutionFlow targetExecutionFlow = getByRequestIdAndCreateTime(executionFlow);
        if (targetExecutionFlow == null || targetExecutionFlow.getStatus() != ExecutionFlow.FlowStatus.INITIALIZED) {
            return null;
        }

        updateByRequestId(targetExecutionFlow, executionFlow); // 会更新extendInfo和Status

        // 将更新后的目标流水返回
        targetExecutionFlow.setStatus(executionFlow.getStatus());
        targetExecutionFlow.setExtendInfo(executionFlow.getExtendInfo());
        targetExecutionFlow.setFailReason(executionFlow.getFailReason());
        return targetExecutionFlow;
    }

//    /**
//     * 用流水id来标记状态
//     */
//    public boolean successById(ExecutionFlow executionFlow) {
//        return setStatus(executionFlow, ExecutionFlow.FlowStatus.SUCCEEDED);
//    }
//    public boolean failById(ExecutionFlow executionFlow) {
//        return setStatus(executionFlow, ExecutionFlow.FlowStatus.FAILED);
//    }

    /** 用requestId和createTime找到流水来标记状态和extendInfo executionFlow里需要有RequestIdAndCreateTime */
    public ExecutionFlow success(@NotNull ExecutionFlow executionFlow) {
        executionFlow.setStatus(ExecutionFlow.FlowStatus.SUCCEEDED);
        return setStatusByRequestIdAndCreateTime(executionFlow);
    }

    public ExecutionFlow fail(@NotNull ExecutionFlow executionFlow) {
        return fail(executionFlow, null);
    }

    public ExecutionFlow fail(@NotNull ExecutionFlow executionFlow, String extendInfo) {
        executionFlow.setStatus(ExecutionFlow.FlowStatus.FAILED);
        if (!TextUtils.isEmpty(extendInfo)) {
            executionFlow.setExtendInfo(extendInfo);
            try {
                HashMap<String, String> info = ChannelJSONUtil.parseJson(extendInfo, HashMap.class);
                if (info.containsKey("reason")) {
                    executionFlow.setFailReason(info.get("reason"));
                }
            } catch (Exception ignored) {
                executionFlow.setFailReason(extendInfo);
            }
        }
        return setStatusByRequestIdAndCreateTime(executionFlow);
    }

//    /**
//     * 获取用户所有流水
//     * @param userId 用户id
//     * @param dateString 时间 yyMMdd
//     * @return 流水list
//     */
//    public List<ExecutionFlow> getFlowByUserIdAndDateString(String userId, String dateString) {
//        return executionFlowMapper.getFlowByUserIdAndDateString(userId, dateString);
//    }
//    public List<ExecutionFlow> getFlowByUserIdAndDate(String userId, Date date) {
//        return getFlowByUserIdAndDateString(userId, dateFormat(date));
//    }
//    /**
//     * 获取用户所有成功流水
//     * @param userId 用户id
//     * @param dateString 时间 yyMMdd
//     * @return 流水list
//     */
//    public List<ExecutionFlow> getSucceedFlowsOfUserAndDateString(String userId, String dateString) {
//        return executionFlowMapper.getSucceedFlowsOfUserAndDateString(userId, dateString);
//    }
//    public List<ExecutionFlow> getSucceedFlowsOfUserAndDate(String userId, Date date) {
//        return getSucceedFlowsOfUserAndDateString(userId, dateFormat(date));
//    }
//
//    public List<ExecutionFlow> getSucceedPayFlowsOfUserAndDate(String userId, Date date) {
//        return getSucceedPayFlowsOfUserAndDate(userId, dateFormat(date));
//    }

    /** 成功流水相关 */

    public List<ExecutionFlow> getSucceedPayFlowsOfUserAndDate(String userId, String date) {
        return executionFlowMapper.getSucceedPayFlowsOfUserAndDateString(userId, date);
    }
    //    public List<ExecutionFlow> getSucceedPayFlowsAndDateString(Date date) {
//        return getSucceedPayFlowsAndDateString(dateFormat(date));
//    }
    public List<ExecutionFlow> getSucceedPayFlowsAndDateString(String date) {
        return executionFlowMapper.getSucceedPayFlowsAndDateString(date);
    }

    /** pending的remit流水相关 */
    public List<ExecutionFlow> getPendingRemitFlowsByChannelType(String channelType, String date) {
        return executionFlowMapper.getPendingRemitFlowsByChannelType(channelType, date);
    }
    public boolean checkTableExistsWithDate(String dateString) {
        Map<String, String> map = executionFlowMapper.getTablesWithDate(dateString);
        return !CollectionUtils.isEmpty(map);
    }
    /** pending的所有流水相关 */
    public List<ExecutionFlow> getPendingFlowsByChannelType(String channelType, String date) {
        return executionFlowMapper.getPendingFlowsByChannelType(channelType, date);
    }

    public PageVo getUnionPayFlow(QueryExecutionFlowForm flowForm){
        // 验证flowForm.getStarttime 存在性；
        int ef = executionFlowMapper.isTableExist("execution_flow_"+flowForm.getStartTime());
        int efup = executionFlowMapper.isTableExist("execution_flow_union_pay_"+flowForm.getStartTime());

        if(ef + efup == 0){
            throw new ServiceException(ResultCode.ERROR_PARAMETER_WRONG,"此日期流水不存在");
        }

        PageHelper.startPage(flowForm.getPageNum(),flowForm.getPageSize());

        List<UnionFlowQueryVo> lists = executionFlowMapper.getUnionFlowByQueryExecutionFlowForm(flowForm, ef, efup);
        PageInfo info = new PageInfo(lists);
        log.info("-------------list: " + JSONUtil.toJson(lists));

        lists = lists.stream().map(x->{
            StringBuilder tableName = new StringBuilder();
            String channel =  x.getChannel();
            if(channel !=null) {
                String[] split = StringUtils.split(channel,"-");
                var name = split[0].toLowerCase();
                var subNameArr = Arrays.asList(split).subList(1, split.length).toArray(new String[]{});
                var subName = StringUtils.join(subNameArr, "-").toLowerCase();
                tableName.append(name)
                        .append("_channel_bound_relationship_")
                        .append(subName);
                //没办法暂时只能用这种忌讳方法处理了
                ChannelBoundRelationship ship = executionFlowMapper
                        .getChannelUserIdAndCardTypeFromChannelBoundRelationShipByCardId(
                                tableName.toString(),
                                x.getCardId()
                        );
                if (ship != null) {
                    x.setCardType(ship.getCardType().toString());
                    x.setChannelUserId(ship.getChannelUserId());
                }
            }

            return x;
        }).collect(Collectors.toList());


        return PageVo.builder().payload(CollectionUtils.arrayToList(lists.toArray())).size((long)info.getPageSize()).page((long)info.getPageNum()).total(info.getTotal()).build();

    }
}
